#pragma once

#include <adapter/adapter.h>
#include <jtag/tapc.h>

#include "cmsisDapIO.h"

struct pending_scan_result;

class cmsisDAP: public openocd::adapter, public tapc
{
public:
    enum DapMode {
        DM_SWD,
        DM_JTAG
    };

public:
    cmsisDAP();

public:
    int selectMode(enum DapMode mode);

protected:
    bool init();
    void deinit();

private:
    virtual int dap_read(struct cmsis_dap *dap, int timeout_ms) = 0;
    virtual int dap_write(struct cmsis_dap *dap, int len, int timeout_ms) = 0;

private:
    virtual int execute_queue(struct list_head *chead) final;

private:
    int execute(struct jtag_command *cmd);
    void cmsis_dap_execute_sleep(struct jtag_command *cmd);    
    int cmsis_dap_execute_tlr_reset(struct jtag_command *cmd);
    void cmsis_dap_execute_scan(struct jtag_command *cmd);
    void cmsis_dap_execute_pathmove(struct jtag_command *cmd);
    void cmsis_dap_execute_runtest(jtag_command *cmd);
    void cmsis_dap_execute_stableclocks(struct jtag_command *cmd);
    void cmsis_dap_execute_tms(struct jtag_command *cmd);

private:
    void cmsis_dap_end_state(tap_state_t state);
    void cmsis_dap_pathmove(int num_states, tap_state_t *path);
    void cmsis_dap_add_tms_sequence(const uint8_t *sequence, int s_len);
    void cmsis_dap_add_jtag_sequence(int s_len, const uint8_t *sequence, int s_offset,
                                     bool tms, uint8_t *tdo_buffer, int tdo_buffer_offset);
    void cmsis_dap_state_move(void);
    void cmsis_dap_runtest(int num_cycles);
    void cmsis_dap_stableclocks(int num_cycles);
    int cmsis_dap_cmd_dap_swj_sequence(uint8_t s_len, const uint8_t *sequence);

private:
    int cmsis_dap_flush();
    int _add_jtag_sequence(int s_len, const uint8_t *sequence, int s_offset,
                           bool tms, uint8_t *tdo_buffer, int tdo_buffer_offset);
    int cmsis_dap_cmd_dap_connect(uint8_t mode);
    int cmsis_dap_xfer(struct cmsis_dap *dap, int txlen);

protected:
    struct cmsis_dap _dap;

private:
    uint8_t *queued_seq_buf;
    int queued_seq_count;
    int queued_seq_buf_end;

    struct cmsis_dap *cmsis_dap_handle;
    struct pending_scan_result *pending_scan_results;
    int pending_scan_result_count;
    int queued_seq_tdo_ptr;
};
